﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.DirectoryServices;
    using System.Security.Principal;
    using System.Diagnostics;
    using System.Threading;
    #endregion

    /// <summary>
    /// Objects that are Users, Groups, or Computers
    /// </summary>
    [Serializable]
    public class UserGroupComputer : ADBaseObjectProperties, IUserGroupComputer {

        #region Members
        public static readonly new string[] AttributesToGet;

        public string DisplayName { get; protected set; }

        public string DomainCNPlusName {
            get {
                if (!string.IsNullOrWhiteSpace(this.DomainCN) && !string.IsNullOrWhiteSpace(this.SamAccountName)) {
                    return string.Format(@"{0}\{1}", this.DomainCN, this.SamAccountName);
                }
                else return string.Empty;
            }
        }

        public string DomainPlusName {
            get {
                if (!string.IsNullOrWhiteSpace(this.Domain)) {
                    if (!string.IsNullOrWhiteSpace(this.SamAccountName)) {
                        return string.Format(@"{0}\{1}", this.Domain, this.SamAccountName);
                    }
                    if (!string.IsNullOrWhiteSpace(this.Name)) {
                        return string.Format(@"{0}\{1}", this.Domain, this.Name);
                    }
                }

                return string.Empty;
            }
        }

        public string SamAccountName {
            get { return samAccountName; }
            protected set {
                if (string.IsNullOrWhiteSpace(samAccountName)) {
                    samAccountName = value;
                }
                // enable changing the case of the username, but not the actual value
                else if (string.Equals(samAccountName, value, StringComparison.OrdinalIgnoreCase)) {
                    samAccountName = value;
                }
            }
        }
        private string samAccountName;

        public SamAccountType SamAccountType { get; protected set; }

        public IReadOnlyList<SecurityIdentifier> SIDHistory { get; protected set; }

        #endregion

        #region Constructors
        static UserGroupComputer() {
            var attributesToGet = new List<string>();
            attributesToGet.AddRange(new string[]
            {
                "displayName",
                "samAccountName",
                "samAccountType",
                "sidHistory"
            });

            attributesToGet.AddRange(ADBaseObjectProperties.AttributesToGet);

            AttributesToGet = attributesToGet.Distinct().ToArray();
            attributesToGet = null;
        }
        public UserGroupComputer() {
            this.Initialize();
        }

        public UserGroupComputer(DirectoryEntry directoryEntry, bool destroyInputObject = true)
            : base(directoryEntry, destroyInputObject) {
            if (this.GetType().Name == typeof(UserGroupComputer).Name) {
                this.Attributes = null;
            }
        }

        public UserGroupComputer(SearchResult result, bool destroyInputObject = true)
            : base(result, destroyInputObject) {
            if (this.GetType().Name == typeof(UserGroupComputer).Name) {
                this.Attributes = null;
            }
        }

        public UserGroupComputer(List<string> ldifOutput)
            : base(ldifOutput) {
            if (this.GetType().Name == typeof(UserGroupComputer).Name) {
                this.Attributes = null;
            }
        }
        #endregion

        #region Methods
        protected override void Initialize() {
            base.Initialize();

            this.DisplayName = string.Empty;
            this.ObjectSid = null;
            this.SamAccountName = string.Empty;
            this.SIDHistory = new List<SecurityIdentifier>();
        }

        protected override void ProcessResults() {

            try {
                base.ProcessResults();

                if (this.Attributes.ContainsKey("displayName")) this.DisplayName = this.Attributes["displayName"][0].ToString();
                if (this.Attributes.ContainsKey("samAccountName")) this.SamAccountName = this.Attributes["samAccountName"][0].ToString();
                if (this.Attributes.ContainsKey("samAccountType")) this.SamAccountType = (SamAccountType)Convert.ToUInt32(this.Attributes["samAccountType"][0]);
                if (this.Attributes.ContainsKey("sIDHistory")) {
                    var sidHistory = new List<SecurityIdentifier>();
                    for (int index = 0; index < this.Attributes["sIDHistory"].Length; index++) {
                        if (this.Attributes["sIDHistory"][index] as byte[] != null) {
                            sidHistory.Add(new SecurityIdentifier((byte[])this.Attributes["sIDHistory"][index], 0));
                        }
                        else {
                            sidHistory.Add(new SecurityIdentifier(this.Attributes["sIDHistory"][index].ToString().FromBase64(), 0));
                        }
                    }
                    this.SIDHistory = new List<SecurityIdentifier>(sidHistory);
                }

                this.IsValid = !string.IsNullOrWhiteSpace(this.DN)
                    && this.ObjectClass.Any(x =>
                        x.Equals("User", StringComparison.OrdinalIgnoreCase)
                        || x.Equals("Group", StringComparison.OrdinalIgnoreCase)
                        || x.Equals("Computer", StringComparison.OrdinalIgnoreCase));
            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }
        }
        #endregion
    }
}
